package com.fowo.api.datainterface.service.impl.implCore;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.fowo.api.datainterface.aspect.BaseAspect;
import com.fowo.api.datainterface.constants.Constants;
import com.fowo.api.datainterface.constants.DataTypeKind;
import com.fowo.api.datainterface.constants.RequestMethodKind;
import com.fowo.api.datainterface.model.DataContextModel;
import com.fowo.api.datainterface.service.serviceCore.BaseInvokeService;
import com.fowo.api.datainterface.service.serviceCore.BaseToService;
import com.fowo.api.datainterface.service.serviceCore.BaseFromService;
import com.fowo.api.datainterface.util.Common;
import com.fowo.api.datainterface.util.JScriptUtil;
import com.fowo.api.datainterface.util.JsonUtil;
import com.fowo.api.sys.component.ExecuteScriptEngine;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 数据接口 服务实现类
 */
@Service
@Slf4j
@DS("ds24")
@RequiredArgsConstructor
public class ApiServiceImpl implements BaseFromService, BaseToService, BaseInvokeService {

    private final Common common;

    private volatile BaseAspect baseAspect;

    public synchronized BaseAspect getBaseAspect(String type) {
        return ObjUtil.isEmpty(baseAspect) ? new BaseAspect(type) : baseAspect;
    }

    private final JScriptUtil jScriptUtil;

    @Override
    public DataTypeKind getType() {
        return DataTypeKind.Api;
    }

    @Override
    public Object getAuth(DataContextModel.DatainterfaceAuthorityModel invoke) {
        return null;
    }

    @Override
    public Object invoke(DataContextModel.DatainterfaceInvokeModel invoke, Object currentParamsMap, JSONObject currentHeadersMap) {
        // 请求拼接参数
        JSONObject jsonObject = new JSONObject();
        HttpHeaders httpHeaders = new HttpHeaders();
        // 请求地址
        String path = common.convertRequestPath(invoke.getAuthority().getRootPath(),invoke.getInterfaceUrl()) ;
        // 请求方法
        HttpMethod requestMethod = common.convertRequestMethod(invoke.getRequestMethod());
        // 获取请求参数
        JSONObject requestParams = JsonUtil.getJsonToBeanSafe(currentParamsMap,JSONObject.class);
        // 获取请求头参数
        String requestHeaders = invoke.getRequestHeaders();
        //参数放置位置(暂时预留)
        if (HttpUtil.isHttp(path) || HttpUtil.isHttps(path)) {
            //请求参数解析
            if (StrUtil.equalsIgnoreCase(RequestMethodKind.Get.getValue(), requestMethod.name())) {
                path = common.processUrlArgs(requestParams, path, null);
            } else if (StrUtil.equalsIgnoreCase(RequestMethodKind.Post.getValue(), requestMethod.name()) ||
                    StrUtil.equalsIgnoreCase(RequestMethodKind.Put.getValue(), requestMethod.name()) ||
                    StrUtil.equalsIgnoreCase(RequestMethodKind.Delete.getValue(), requestMethod.name())) {
                jsonObject = common.processBodyArgs(requestParams, jsonObject, null);
            } else {
                Assert.isTrue(false, "接口 {} ，指定的查询类型 {} 错误 ！", invoke.getEnCode(), requestMethod.name());
            }
            List<JSONObject> requestHeadersListMap = JsonUtil.getJsonToList(requestHeaders);
            httpHeaders = common.processHeaderArgs(currentHeadersMap, httpHeaders, requestHeadersListMap);
            Object res;
            try {
                res = getBaseAspect(invoke.getAuthority().getAppName()).httpRequest(path, requestMethod, jsonObject, httpHeaders,String.class, Constants.Read,StrUtil.EMPTY);
            } catch (Exception ex) {
                throw new RuntimeException(StrUtil.format("API目标接口 {} ，执行 {} 操作 {} 发生异常 ",   invoke.getEnCode(), path, StrUtil.subPre(JsonUtil.getObjectToString(jsonObject), 500), ExceptionUtil.getRootCauseMessage(ex)));
            }
            if (ObjectUtil.isEmpty(res)) {
                throw new RuntimeException(StrUtil.concat(true, "拉取失败或无返回值：", StrUtil.subPre(JsonUtil.getObjectToString(res), 500)));
            }
            return jScriptUtil.callJsFrom(invoke.getDataProcessing(), res == null ? new ArrayList<>() : res, null, null);
        } else {
            Assert.isTrue(false, "接口 {} ，地址 {} 错误 ！",  invoke.getEnCode(), path);
        }
        return null;
    }


    @Override
    public Object invokeFrom(DataContextModel.DatainterfaceFromModel from, JSONObject currentParamsMap, JSONObject currentHeadersMap) {
        // 请求拼接参数
        JSONObject jsonObject = new JSONObject();
        HttpHeaders httpHeaders = new HttpHeaders();
        // 请求地址
        String path = from.getInterfaceUrl();
        // 请求方法
        HttpMethod requestMethod = common.convertRequestMethod(from.getRequestMethod());
        // 获取请求参数
        String requestParams = from.getRequestParams();
        // 获取请求头参数
        String requestHeaders = from.getRequestHeaders();
        //参数放置位置(暂时预留)
        String paramsPlace = from.getParamsPlace();

        if (HttpUtil.isHttp(path) || HttpUtil.isHttps(path)) {
            //请求参数解析
            List<JSONObject> requestParamsListMap = JsonUtil.getJsonToList(requestParams);
            if (CollUtil.isNotEmpty(requestParamsListMap)) {
                if (StrUtil.equalsIgnoreCase(RequestMethodKind.Get.getValue(), requestMethod.name())) {
                    path = common.processUrlArgs(currentParamsMap, path, requestParamsListMap);
                } else if (StrUtil.equalsIgnoreCase(RequestMethodKind.Post.getValue(), requestMethod.name()) ||
                        StrUtil.equalsIgnoreCase(RequestMethodKind.Put.getValue(), requestMethod.name()) ||
                        StrUtil.equalsIgnoreCase(RequestMethodKind.Delete.getValue(), requestMethod.name())) {
                    jsonObject = common.processBodyArgs(currentParamsMap, jsonObject, requestParamsListMap);
                } else {
                    Assert.isTrue(false, "{} 来源接口 {} ，指定的查询类型 {} 错误 ！", StrUtil.concat(true, from.getTaskCode()), from.getEnCode(), requestMethod.name());
                }
            }
            List<JSONObject> requestHeadersListMap = JsonUtil.getJsonToList(requestHeaders);
            httpHeaders = common.processHeaderArgs(currentHeadersMap, httpHeaders, requestHeadersListMap);
            Object res;
            try {
                res = getBaseAspect(from.getAuthority().getAppName()).httpRequest(path, requestMethod, jsonObject, httpHeaders,String.class, Constants.Read,StrUtil.EMPTY);
            } catch (Exception ex) {
                throw new RuntimeException(StrUtil.format("{} API目标接口 {} ，执行 {} 操作 {} 发生异常 ", StrUtil.concat(true, from.getTaskCode()), from.getEnCode(), path, StrUtil.subPre(JsonUtil.getObjectToString(jsonObject), 500), ExceptionUtil.getRootCauseMessage(ex)));
            }
            if (ObjectUtil.isEmpty(res)) {
                throw new RuntimeException(StrUtil.concat(true, "拉取失败或无返回值：", StrUtil.subPre(JsonUtil.getObjectToString(res), 500)));
            }
            return jScriptUtil.callJsFrom(from.getDataProcessing(), res == null ? new ArrayList<>() : res, null, null);
        } else {
            Assert.isTrue(false, "{} 来源接口 {} ，地址 {} 错误 ！", StrUtil.concat(true, from.getTaskCode()), from.getEnCode(), path);
        }
        return null;
    }

    @Override
    public Object invokeTo(DataContextModel.DatainterfaceToModel to, JSONObject currentParamsMap, JSONObject currentHeadersMap) {
        // 请求拼接参数
        JSONObject jsonObject = new JSONObject();
        HttpHeaders httpHeaders = new HttpHeaders();
        // 请求地址
        String path = to.getInterfaceUrl();
        // 请求方法
        HttpMethod requestMethod = common.convertRequestMethod(to.getRequestMethod());
        // 获取请求参数
        String requestParams = to.getRequestParams();
        // 获取请求头参数
        String requestHeaders = to.getRequestHeaders();
        //参数放置位置(暂时预留)
        String paramsPlace = to.getParamsPlace();

        if (HttpUtil.isHttp(path) || HttpUtil.isHttps(path)) {
            //请求参数解析
            List<JSONObject> requestParamsListMap = JsonUtil.getJsonToList(requestParams);
            if (CollUtil.isNotEmpty(requestParamsListMap)) {
                if (StrUtil.equalsIgnoreCase(RequestMethodKind.Get.getValue(), requestMethod.name())) {
                    path = common.processUrlArgs(currentParamsMap, path, requestParamsListMap);
                } else if (StrUtil.equalsIgnoreCase(RequestMethodKind.Post.getValue(), requestMethod.name()) ||
                        StrUtil.equalsIgnoreCase(RequestMethodKind.Put.getValue(), requestMethod.name()) ||
                        StrUtil.equalsIgnoreCase(RequestMethodKind.Delete.getValue(), requestMethod.name())) {
                    jsonObject = common.processBodyArgs(currentParamsMap, jsonObject, requestParamsListMap);
                } else {
                    Assert.isTrue(false, "{} 目标接口 {} ，指定的查询类型 {} 错误 ！", StrUtil.concat(true, to.getTaskCode()), to.getEnCode(), requestMethod.name());
                }
            }
            List<JSONObject> requestHeadersListMap = JsonUtil.getJsonToList(requestHeaders);
            httpHeaders = common.processHeaderArgs(currentHeadersMap, httpHeaders, requestHeadersListMap);
            Object res;
            try {
                res = getBaseAspect(to.getAuthority().getAppName()).httpRequest(path, requestMethod, jsonObject, httpHeaders,String.class, Constants.Write,StrUtil.EMPTY);
            } catch (Exception ex) {
                throw new RuntimeException(StrUtil.format("{} API目标接口 {} ，执行 {} 操作 {} 发生异常 ", StrUtil.concat(true, to.getTaskCode()), to.getEnCode(), path, StrUtil.subPre(JsonUtil.getObjectToString(jsonObject), 500), ExceptionUtil.getRootCauseMessage(ex)));
            }
            return jScriptUtil.callJsFrom(to.getDataProcessing(), res == null ? new ArrayList<>() : res, null, null);
        } else {
            Assert.isTrue(false, "{} 目标接口 {} ，地址 {} 错误 ！", StrUtil.concat(true, to.getTaskCode()), to.getEnCode(), path);
        }
        return null;
    }


}
